﻿using System;
using System.Data.Common;
using System.Reflection;

namespace MingYuanYun.Data.Abstractions
{
	// 参照 https://github.com/nhibernate/nhibernate-core/blob/190fe3c60ffd99a22805be241330fadb74f0177b/src/NHibernate/Driver/ReflectionBasedDriver.cs
	internal class ReflectionBasedDriver
	{
		private const string ReflectionTypedProviderExceptionMessageTemplate =
			"The DbConnection implementation in the assembly {0} could not be found. Ensure that the assembly {0} is located in the application directory.";

		private readonly ReflectionDriveConnectionProvider _connectionProvider;

		protected Version DriverVersion { get; }

		protected ReflectionBasedDriver(string driverAssemblyName, string connectionTypeName)
		{
			var connectionType = TypeFromAssembly(connectionTypeName, driverAssemblyName);

			if (connectionType == null)
			{
				throw new ArgumentNullException(string.Format(ReflectionTypedProviderExceptionMessageTemplate, driverAssemblyName));
			}

			_connectionProvider = new ReflectionDriveConnectionProvider(connectionType);

			DriverVersion = connectionType.Assembly.GetName().Version;
		}

		public DbConnection CreateConnection(string connectionString)
		{
			var connection = _connectionProvider.CreateConnection();

			connection.ConnectionString = connectionString;

			return connection;
		}

		private static Type TypeFromAssembly(string connectionTypeName, string driverAssemblyName)
		{
			try
			{
				// Try to get the type from an already loaded assembly
				var type = Type.GetType($"{connectionTypeName}, {driverAssemblyName}");

				if (type != null)
				{
					return type;
				}

				if (driverAssemblyName == null)
				{
					return null;
				}

				return Assembly.Load(driverAssemblyName)?.GetType(connectionTypeName, false);
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
}
